package org.jeecg.modules.system.filter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.cache.PermissionCodeCache;
import org.jeecg.common.constant.enums.SysLogOperateType;
import org.jeecg.common.constant.enums.SysLogType;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.vo.PermissionsInfoVo;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.mapper.SysUserMapper;
import org.jeecg.modules.system.util.EmailUtil;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sgcc.isc.ualogin.client.util.ISCAuthRouter;
import com.sgcc.isc.ualogin.client.util.IscSSOResourceUtil;
import com.sgcc.isc.ualogin.client.vo.IscSSOUserBean;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class IscAccessInterceptFilter implements Filter {

	private static volatile List<String> excludeSuffixList = new ArrayList<String>();

	private List<String> whiteLists = new ArrayList<String>();

	private String appid;

	private static String isc_filter_server = null;

	private static volatile String isc_kickback_url = null;

	private boolean canAccess(String appid, String userid, String username, String url, String format, String clientIP, String requestUrl) {
		String dbUserId = userid;
		boolean result = false;
		String data = "";
		String filter_server = isc_filter_server;
		if (clientIP != null && clientIP != "")
			userid = String.valueOf(userid) + "," + clientIP;
		filter_server = String.valueOf(filter_server) + "/filter/url/" + appid + "/" + userid + "/" + url;
		if (format != null)
			filter_server = String.valueOf(filter_server) + "/" + format;
		HttpClient client = new HttpClient();
		log.info(String.format("【越权校验】userid:%s  username:%s  url:%s  越权接口请求开始，请求地址: %s", userid, username, requestUrl, filter_server));
		GetMethod get = new GetMethod(filter_server);
		try {
			int status = client.executeMethod((HttpMethod) get);
			if (status == 200) {
				InputStream responseBody = get.getResponseBodyAsStream();
				BufferedReader reader = new BufferedReader(new InputStreamReader(responseBody, "UTF-8"));
				if (reader != null) {
					data = reader.readLine();
					if ("true".equals(data)) {
						result = true;
						log.info(String.format("【越权校验】userid:%s  username:%s  url:%s ISC权限通过", userid, username, requestUrl));
//						IscAccessList accessList = SpringUtil.getBean(IscAccessList.class);
//						if(accessList != null) {
//							if(accessList.getUrlList().contains(requestUrl)){
//								 IResourceService resourceService = AdapterFactory.getResourceService();
//								 try {
//									boolean re =resourceService.hasPermitURLObj(dbUserId,appid,requestUrl);
//									log.info("check access res:"+re);
//									result = re;
//								 } catch (Exception e) {
//									log.error("check access error :"+e);
//									e.printStackTrace();
//								}
//							}
//						}
						
					} else {
						log.error(String.format("【越权校验】userid:%s username:%s  url:%s 越权，ISC没有权限", userid, username, requestUrl));

						PermissionsInfoVo vo = PermissionCodeCache.getByUrl(requestUrl);
						if (vo != null) {
							SysUserMapper sysUserMapper = (SysUserMapper) SpringContextUtils.getBean(SysUserMapper.class);
							List<SysUser> users = sysUserMapper.selectList(new QueryWrapper<SysUser>().eq("third_id", dbUserId));
							String userName = dbUserId;
							String userId = null;
							if (users != null && users.size() > 0) {
								userName = users.get(0).getRealname();
								userId = users.get(0).getId();
							}
							ISysBaseAPI sysBaseAPI = (ISysBaseAPI) SpringContextUtils.getBean("sysBaseAPI");
							String content = String.format("%s试图访问%s(%s)进行了越权操作,已被系统拦截", userName, vo.getName(), vo.getUrl());
							if(StringUtils.isNotBlank(vo.getName())) {
								sysBaseAPI.addLog(vo.getName()+"("+vo.getUrl()+")", SysLogType.ALARM, SysLogOperateType.UNAUTHORIZED, userId, content, "越权告警拦截-"+vo.getName());
							}
							// 发送邮件
							EmailUtil emailUtil = SpringContextUtils.getBean(EmailUtil.class);
							emailUtil.sendEmail("越权告警", content);
						}
					}
				}
			} else {
				result = true;
			}
		} catch (HttpException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			get.releaseConnection();
		}
		return result;
	}

	public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) arg0;
		HttpServletResponse response = (HttpServletResponse) arg1;
		String requestUrl = request.getRequestURI().replace("//", "/");
		
		RedisUtil redisUtil = (RedisUtil) SpringContextUtils.getBean(RedisUtil.class);
		Object result = redisUtil.get("performance");
		if (result != null && (Boolean) result == true) {
			arg2.doFilter(arg0, arg1);
			log.info(String.format("【越权校验】 url:%s 跳过越权", requestUrl));
			return;
		}
		
		HttpSession session = request.getSession(false);
		if (session == null) {
			arg2.doFilter(arg0, arg1);
		} else {
			try {
				String clientIP = getIpAddr(request);
				if (StringUtils.isEmpty(clientIP))
					clientIP = "unknown";
				ISCAuthRouter router = ISCAuthRouter.getRouter();
				if (router.isRouteToLocal((ServletRequest) request, (ServletResponse) response, arg2))
					return;
				boolean isWhite = false;

				if (requestUrl.startsWith("/mesh-controller")) {
					requestUrl = requestUrl.substring("/mesh-controller".length(), requestUrl.length());
				}
				log.info(String.format("【越权校验】 url:%s 开始", requestUrl));
				String[] uris = requestUrl.split("\\?");
				if (uris[0].contains("signout")) {
					arg2.doFilter(arg0, arg1);
					return;
				}
				// boolean prjSourceUrl = patternUrl("/.*/.*/.*", uris[0]);
				// if (!prjSourceUrl) {
				// arg2.doFilter(arg0, arg1);
				// return;
				// }
				int i;
				for (i = 0; i < excludeSuffixList.size(); i++) {
					if (requestUrl.endsWith(excludeSuffixList.get(i))) {
						isWhite = true;
						break;
					}
				}
				if (!isWhite)
					for (i = 0; i < this.whiteLists.size(); i++) {
						if (this.whiteLists.get(i) != null) {
							boolean flag = uris[0].contains(this.whiteLists.get(i));
							if (flag) {
								isWhite = flag;
								break;
							}
						}
					}
				if (!isWhite) {
					IscSSOUserBean user = IscSSOResourceUtil.getIscUserBean(request);
					if (user != null && user.getIscUserId() != null) {
						String url = null;
						String format = null;
						if (requestUrl.contains(".")) {
							url = requestUrl.split("\\.")[0];
							format = requestUrl.split("\\.")[1];
						} else {
							format = "@";
							url = requestUrl;
						}
						url = url.replaceAll("\\/", "\\*").replaceAll("\\//", "\\*");
						if (canAccess(this.appid, user.getIscUserId(), user.getIscUserSourceId(), url, format, clientIP, requestUrl)) {
							arg2.doFilter(arg0, arg1);
						} else {
							session.invalidate();
							StringBuilder outPrint = new StringBuilder();
							outPrint.append("您没有权限");
							if (isc_kickback_url != null) {
								// outPrint.append("location.href='").append(isc_kickback_url).append("';");
							} else {
								log.info("****************************" + this.appid);
							}
							outPrintMsg(response, outPrint.toString());
						}
					} else {
						response.setStatus(405);
						StringBuilder outPrint = new StringBuilder();
						outPrint.append("未登录");
						outPrintMsg(response, outPrint.toString());
					}
				} else {
					arg2.doFilter(arg0, arg1);
				}
			} catch (Exception e) {
				log.error(String.format("【越权校验】 url:%s 失败", requestUrl), e);
				arg2.doFilter(arg0, arg1);
			}
		}
	}

	public void init(FilterConfig arg0) throws ServletException {
		isc_filter_server = arg0.getInitParameter("iscFilterServer");
		this.appid = arg0.getServletContext().getInitParameter("appid");
		isc_kickback_url = arg0.getInitParameter("iscKickBackUrl");
		if (isc_filter_server == null)
			throw new ServletException("name isc_filter_server");
		if (this.appid == null)
			throw new ServletException("name appid");
		if (this.appid == null)
			throw new ServletException("");
		String excludeSuffix = arg0.getInitParameter("excludeSuffix");
		if (excludeSuffix != null) {
			String[] excludeSuffixArray = excludeSuffix.split(",");
			for (int i = 0; i < excludeSuffixArray.length; i++)
				excludeSuffixList.add("." + excludeSuffixArray[i]);
		} else {
			excludeSuffixList.add(".js");
			excludeSuffixList.add(".css");
			excludeSuffixList.add(".gif");
			excludeSuffixList.add(".png");
			excludeSuffixList.add(".htm");
			excludeSuffixList.add(".jpg");
			excludeSuffixList.add(".as");
			excludeSuffixList.add(".swf");
			excludeSuffixList.add(".ico");
			excludeSuffixList.add(".eot");
			excludeSuffixList.add(".xsd");
			excludeSuffixList.add(".jar");
		}
		String exclude = arg0.getInitParameter("exclude");
		if (exclude != null) {
			String[] excludes = exclude.split(",");
			for (int i = 0; i < excludes.length; i++)
				this.whiteLists.add(excludes[i]);
		}
	}

	private static boolean patternUrl(String patternUrl, String url) {
		patternUrl = patternUrl.toLowerCase().trim();
		url = url.toLowerCase().trim();
		boolean flag = Pattern.compile(patternUrl, 2).matcher(url).matches();
		return flag;
	}

	public void destroy() {
	}

	public String getServiceUrl(String serviceUrl) {
		String serviceUrl_ = "";
		String[] s1 = serviceUrl.split(":");
		if (s1.length > 2) {
			if (StringUtils.isEmpty(s1[2])) {
				serviceUrl_ = String.valueOf(s1[0]) + ":" + s1[1];
			} else if (s1[2].contains("/")) {
				String[] s2 = s1[2].split("/");
				if (s2.length > 1) {
					if (StringUtils.isEmpty(s2[1])) {
						serviceUrl_ = String.valueOf(s1[0]) + ":" + s1[1] + ":" + s2[0];
					} else {
						serviceUrl_ = String.valueOf(s1[0]) + ":" + s1[1] + ":" + s2[0] + "/" + s2[1];
					}
				} else {
					serviceUrl_ = String.valueOf(s1[0]) + ":" + s1[1] + ":" + s2[0];
				}
			} else {
				serviceUrl_ = String.valueOf(s1[0]) + ":" + s1[1] + ":" + s1[2];
			}
		} else if (s1.length == 2) {
			Pattern p = Pattern.compile("(?<=//|)((\\w)+\\.)+\\w+");
			if (s1[1].contains("//"))
				s1[1] = s1[1].replace("//", "");
			String[] s2 = s1[1].split("/");
			if (s2.length >= 2) {
				serviceUrl_ = String.valueOf(s1[0]) + "//" + s2[0] + "/" + s2[1];
			} else {
				Matcher m = p.matcher(serviceUrl);
				if (m.find())
					serviceUrl_ = String.valueOf(s1[0]) + "//" + m.group();
			}
		} else if (s1.length == 1) {
			Pattern p = Pattern.compile("(?<=//|)((\\w)+\\.)+\\w+");
			Matcher m = p.matcher(serviceUrl);
			if (m.find())
				serviceUrl_ = String.valueOf(s1[0]) + "//" + m.group();
		} else {
			serviceUrl_ = String.valueOf(s1[0]) + "//" + s1[0];
		}
		return serviceUrl_;
	}

	private String getIpAddr(HttpServletRequest request) {
		String ipAddress = request.getHeader("x-forwarded-for");
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress))
			ipAddress = request.getHeader("Proxy-Client-IP");
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress))
			ipAddress = request.getHeader("WL-Proxy-Client-IP");
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
			ipAddress = request.getRemoteAddr();
			if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {
				InetAddress inet = null;
				try {
					inet = InetAddress.getLocalHost();
				} catch (UnknownHostException e) {
					e.printStackTrace();
				}
				ipAddress = inet.getHostAddress();
			}
		}
		if (ipAddress != null && ipAddress.length() > 15)
			if (ipAddress.indexOf(",") > 0)
				ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
		return ipAddress.replace("\\", "");
	}

	private void outPrintMsg(HttpServletResponse response, String msg) {
		try {
			response.setContentType("text/html;charset=utf-8");
			response.setCharacterEncoding("utf-8");
			response.getWriter().print(msg);
			response.getWriter().close();
		} catch (Exception e) {
			log.equals(e.getMessage());
		}
	}
}